package cz.semjob.document.processing;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import cz.semjob.linguistic.reader.LanguageConfig;

public class DocumentInstance implements IIndexedPart {
	
	private final List<DocumentSentence> sentences;
	
	private final String text;
	
	private final LanguageConfig languageConfig; 
	
	private final String fileName;
	
	public DocumentInstance(String text, LanguageConfig lanConfig, String fileName) {
		super();
		this.sentences = new ArrayList<DocumentSentence>();
		this.text = text;
		this.languageConfig = lanConfig;
		this.fileName = fileName;
	}
	
	public void addSentence(DocumentSentence documentSentence) {
		this.sentences.add(documentSentence);
	}
	
	public List<DocumentSentence> getSentences() {
		return sentences;
	}

	public int getStartIndex() {
		return 0;
	}

	public int getEndIndex() {
		if (sentences.isEmpty()) {
			return 0;
		} else {
			return sentences.get(sentences.size()-1).getEndIndex();
		}
	}

	public String getText() {
		return text;
	}
	
	public int getSentencesCount() {
		return this.sentences.size();
	}
	
	public DocumentSentence getSentenceByStartIndex(int startIndex) {
		for (DocumentSentence sentence : sentences) {
			if (sentence.getStartIndex()>= startIndex && startIndex < sentence.getEndIndex()) {
				return sentence;
			}
		}
		return null;
	}
	
	public LanguageConfig getLanguageConfig() {
		return languageConfig;
	}
	
	public String getFileName() {
		return fileName;
	}

	public List<DocumentWord> getWordsByIndexes(int startIndex, int endIndex) {
		List<DocumentWord> documentWords =  new ArrayList<DocumentWord>();
		for (DocumentSentence sentence : sentences) {
			List<DocumentWord> sentenceWords = sentence.getWordsByIndexes(startIndex, endIndex);
			if (!sentenceWords.isEmpty()) {
				documentWords.addAll(sentenceWords);
			}
		}
		return documentWords;
	}
	
	/**
	 * Gets all dependecy paths for each sentence in the document.
	 * 
	 * @return
	 */
	public Set<List<DocumentWord>> getAllDependecyPaths() {
		Set<List<DocumentWord>> dependencyPaths = new HashSet<List<DocumentWord>>();
		for (DocumentSentence sentence : this.getSentences()) {
			Set<List<DocumentWord>> previousStepPaths = new HashSet<List<DocumentWord>>();
			// initializing dependecy paths, starting by adding each word of
			// sentence
			for (DocumentWord sentenceWord : sentence.getWords()) {
				previousStepPaths.add(Arrays.asList(sentenceWord));
			}
			dependencyPaths.addAll(previousStepPaths);
			for (int i = 1; i < sentence.getWordsCount(); i++) {
				Set<List<DocumentWord>> currentStepPaths = getDependencyPathStep(previousStepPaths);
				dependencyPaths.addAll(currentStepPaths);
				previousStepPaths = currentStepPaths;
			}

		}
		return dependencyPaths;
	}

	private Set<List<DocumentWord>> getDependencyPathStep(Set<List<DocumentWord>> previousStepPaths) {
		Set<List<DocumentWord>> newStepPaths = new HashSet<List<DocumentWord>>();
		for(List<DocumentWord> previousPath : previousStepPaths) {
			DocumentWord firstWord = previousPath.get(0);
			DocumentWord firstWordHead = firstWord.getDependencyWord();
			if (firstWordHead != null) {
				List<DocumentWord> newPath = new ArrayList<DocumentWord>(previousPath);
				newPath.add(0, firstWordHead);
				newStepPaths.add(newPath);
			}
		}
		return newStepPaths;
	}

	
	
	@Override
	public String toString() {
		return "DocumentInstance [fileName=" + fileName + ", text=" + text + "]";
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result
				+ ((fileName == null) ? 0 : fileName.hashCode());
		result = prime * result + ((text == null) ? 0 : text.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		DocumentInstance other = (DocumentInstance) obj;
		if (fileName == null) {
			if (other.fileName != null)
				return false;
		} else if (!fileName.equals(other.fileName))
			return false;
		if (text == null) {
			if (other.text != null)
				return false;
		} else if (!text.equals(other.text))
			return false;
		return true;
	}
	
	

}
